import fs from 'node:fs'
import { test, expect } from '../playwright.extend'
import copyServiceWorker from '../../../config/copyServiceWorker'
import packageJson from '../../../package.json' assert { type: 'json' }
// @ts-expect-error Importing a Javascript module.
import { SERVICE_WORKER_SOURCE_PATH } from '../../../config/constants.js'

test('activates the worker without errors given the latest integrity', async ({
  loadExample,
  spyOnConsole,
  fetch,
}) => {
  const consoleSpy = spyOnConsole()
  await loadExample(
    new URL('./integrity-check-valid.mocks.ts', import.meta.url),
  )

  expect(consoleSpy.get('error')).toBeUndefined()

  const res = await fetch('https://example.com/users/octocat')
  const body = await res.json()

  expect(res.fromServiceWorker()).toBe(true)
  expect(body).toEqual({
    mocked: true,
  })
})

test('errors when activating the worker with an outdated integrity', async ({
  loadExample,
  spyOnConsole,
  fetch,
  waitFor,
}) => {
  const TEMP_SERVICE_WORKER_PATH = new URL(
    '../../tmp/mockServiceWorker-outdated.js',
    import.meta.url,
  ).pathname

  // Manually create a Service Worker file with invalid integrity
  await copyServiceWorker(
    SERVICE_WORKER_SOURCE_PATH,
    TEMP_SERVICE_WORKER_PATH,
    'intentionally-invalid-checksum',
  )

  const consoleSpy = spyOnConsole()
  await loadExample(
    new URL('./integrity-check-invalid.mocks.ts', import.meta.url),
    {
      skipActivation: true,
      beforeNavigation(compilation) {
        compilation.use((router) => {
          router.use('/', (_, res, next) => {
            // Appended router are relative to the compilation path.
            // Allow the nested worker script to control the root scope.
            res.setHeader('Service-Worker-Allowed', '/')
            next()
          })

          router.get('/mockServiceWorker-outdated.js', (_, res) => {
            return res
              .set('content-type', 'application/javascript')
              .send(fs.readFileSync(TEMP_SERVICE_WORKER_PATH, 'utf8'))
          })
        })
      },
    },
  )

  await waitFor(() => {
    // Produces a meaningful error in the browser's console.
    expect(consoleSpy.get('warning')).toEqual(
      expect.arrayContaining([
        `[MSW] The currently registered Service Worker has been generated by a different version of MSW (${packageJson.version}) and may not be fully compatible with the installed version.

It's recommended you update your worker script by running this command:

  \u2022 npx msw init <PUBLIC_DIR>

You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`,
      ]),
    )
  })

  // Still keeps the mocking enabled.
  const res = await fetch('https://example.com/users/octocat')
  const body = await res.json()

  expect(res.fromServiceWorker()).toBe(true)
  expect(body).toEqual({
    mocked: true,
  })

  fs.unlinkSync(TEMP_SERVICE_WORKER_PATH)
})
